home *** CD-ROM | disk | FTP | other *** search
/ SIGGRAPH 2002 Course Notes / SIGGRAPH 2002 - Course Notes - Disc 1.iso / pc / notes / 16 / supplemental-material / Gritz / bake.C next >
Encoding:
C/C++ Source or Header  |  2002-04-05  |  6.0 KB  |  206 lines

  1. // bake.C -- code for an Entropy DSO shadeop implementing the "bake" function.
  2. //
  3. // The function prototype for bake is:
  4. //    void bake (string file, float s, float t, TYPE val)
  5. // where TYPE may be any of {float, color, point, vector, normal}.
  6. // The bake function writes (s,t,val) tuples to the given filename,
  7. // which may later be processed in a variety of ways.
  8. //
  9. // "bake" is (c) Copyright 2002 by Larry Gritz.  It was developed
  10. // for the SIGGRAPH 2002, course #16, "RenderMan in Production."
  11. // This code may be modified and/or redistributed, but only if it 
  12. // contains the original attribution above and a reference to the
  13. // SIGGRAPH 2002 course notes in which it appears.
  14.  
  15.  
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <malloc.h>
  19. #include <map>
  20. #include <string>
  21. #include <pthread.h>
  22.  
  23.  
  24. //////////////////////////////////////////////////////////////////////////
  25. // Declarations -- this is all boilerplate and is necessary for the
  26. // shader compiler and renderer to understand what functions are 
  27. // implemented in this DSO and what arguments they take.
  28. //////////////////////////////////////////////////////////////////////////
  29.  
  30. #include "dsoshadeop.h"
  31.  
  32. extern "C" {
  33.  
  34. EXPORT int protocol_version = DS_PROTOCOL_VERSION;
  35.  
  36. EXPORT DS_DispatchTableEntry bake_shadeops[] = {
  37.     { "void bake_f (string, float, float, float)", "bake_init", "bake_done" },
  38.     { "void bake_3 (string, float, float, color)", "bake_init", "bake_done" },
  39.     { "void bake_3 (string, float, float, point)", "bake_init", "bake_done" },
  40.     { "void bake_3 (string, float, float, vector)", "bake_init", "bake_done" },
  41.     { "void bake_3 (string, float, float, normal)", "bake_init", "bake_done" },
  42.     { "", "", "" }
  43. };
  44.  
  45. EXPORT void *bake_init (int, void *);
  46. EXPORT void bake_done (void *data);
  47. EXPORT int bake_f (void *data, int nargs, void **args);
  48. EXPORT int bake_3 (void *data, int nargs, void **args);
  49.  
  50. };  /* extern "C" */
  51.  
  52.  
  53.  
  54. //////////////////////////////////////////////////////////////////////////
  55. // Implementation
  56. //////////////////////////////////////////////////////////////////////////
  57.  
  58. const int batchsize = 10240;  // elements to buffer before writing
  59.  
  60. // Make sure we're thread-safe on those file writes
  61. static pthread_mutex_t mutex;
  62. static pthread_once_t once_block = PTHREAD_ONCE_INIT;
  63.  
  64. static void ptinitonce (void)
  65. {
  66.     pthread_mutex_init (&mutex, NULL);
  67. }
  68.  
  69.  
  70.  
  71. class BakingChannel {
  72.     // A "BakingChannel" is the buffer for a single baking output file.
  73.     // We buffer up samples until "batchsize" has been accepted, then
  74.     // write them all at once.  This keeps us from constantly accessing
  75.     // the disk.  Note that we are careful to use a mutex to keep 
  76.     // simultaneous multithreaded writes from clobbering each other.
  77. public:
  78.     // Constructors
  79.     BakingChannel (void) : filename(NULL), data(NULL), buffered(0) { }
  80.     BakingChannel (const char *_filename, int _elsize) {
  81.     init (_filename, _elsize);
  82.     }
  83.  
  84.     // Initialize - allocate memory, etc.
  85.     void init (const char *_filename, int _elsize) {
  86.     elsize = _elsize+2;
  87.     buffered = 0;
  88.     data = new float [elsize*batchsize];
  89.     filename = strdup (_filename);
  90.     pthread_once (&once_block, ptinitonce);
  91.     }
  92.  
  93.     // Destructor: write buffered output, close file, deallocate
  94.     ~BakingChannel () {
  95.     writedata();
  96.     free (filename);
  97.     delete [] data;
  98.     }
  99.  
  100.     // Add one more data item
  101.     void moredata (float s, float t, float *newdata) {
  102.     if (buffered >= batchsize)
  103.         writedata();
  104.     float *f = data + elsize*buffered;
  105.     f[0] = s;
  106.     f[1] = t;
  107.     for (int j = 2;  j < elsize;  ++j)
  108.         f[j] = newdata[j-2];
  109.     ++buffered;
  110.     }
  111.  
  112. private:
  113.     int elsize;     // element size (e.g., 3 for colors)
  114.     int buffered;   // how many elements are currently buffered
  115.     float *data;    // pointer to the allocated buffer (new'ed)
  116.     char *filename; // pointer to filename (strdup'ed)
  117.  
  118.     // Write any buffered data to the file
  119.     void writedata (void) {
  120.     if (buffered > 0 && filename != NULL) {
  121.         pthread_mutex_lock (&mutex);
  122.         FILE *file = fopen (filename, "a");
  123.         float *f = data;
  124.         for (int i = 0;  i < buffered;  ++i, f += elsize) {
  125.         for (int j = 0;  j < elsize;  ++j)
  126.             fprintf (file, "%g ", f[j]);
  127.         fprintf (file, "\n");
  128.         }
  129.         fclose (file);
  130.         pthread_mutex_unlock (&mutex);
  131.     }
  132.     buffered = 0;
  133.     }
  134. };
  135.  
  136.  
  137.  
  138. typedef std::map<std::string, BakingChannel> BakingData;
  139. // We keep a mapping of strings (filenames) to bake data (BakingChannel).
  140.  
  141.  
  142. // DSO shadeop Initilizer -- allocate and return a new BakingData
  143. EXPORT void *bake_init (int, void *)
  144. {
  145.     BakingData *bd = new BakingData;
  146.     return (void *)bd;
  147. }
  148.  
  149.  
  150.  
  151. // DSO shadeop cleanup -- destroy the BakingData
  152. EXPORT void bake_done (void *data)
  153. {
  154.     BakingData *bd = (BakingData *) data;
  155.     delete bd;  // Will destroy bd, and in turn all its BakingChannel's
  156. }
  157.  
  158.  
  159.  
  160. // Workhorse routine -- look up the channel name, add a new BakingChannel
  161. // if it doesn't exist, add one point's data to the channel.
  162. void
  163. bake (BakingData *bd, const std::string &name,
  164.       float s, float t, int elsize, float *data)
  165. {
  166.     BakingData::iterator found = bd->find (name);
  167.     if (found == bd->end()) {
  168.     // This named map doesn't yet exist
  169.     (*bd)[name] = BakingChannel();
  170.     found = bd->find (name);
  171.     BakingChannel &bc (found->second);
  172.     bc.init (name.c_str(), elsize);
  173.     bc.moredata (s, t, data);
  174.     } else {
  175.     BakingChannel &bc (found->second);
  176.     bc.moredata (s, t, data);
  177.     }
  178. }
  179.  
  180.  
  181.  
  182. // DSO shadeop for baking a float -- just call bake with appropriate args
  183. EXPORT int bake_f (void *data, int nargs, void **args)
  184. {
  185.     BakingData *bd = (BakingData *) data;
  186.     std::string name (*((char **) args[1]));
  187.     float *s = (float *) args[2];
  188.     float *t = (float *) args[3];
  189.     float *bakedata = (float *) args[4];
  190.     bake (bd, name, *s, *t, 1, bakedata);
  191.     return 0;
  192. }
  193.  
  194.  
  195. // DSO shadeop for baking a triple -- just call bake with appropriate args
  196. EXPORT int bake_3 (void *data, int nargs, void **args)
  197. {
  198.     BakingData *bd = (BakingData *) data;
  199.     char **name = (char **) args[1];
  200.     float *s = (float *) args[2];
  201.     float *t = (float *) args[3];
  202.     float *bakedata = (float *) args[4];
  203.     bake (bd, *name, *s, *t, 3, bakedata);
  204.     return 0;
  205. }
  206.